/******************************************************************************/
/*! 
    HeapManager.h
    [2012]

    \File		  HeapManager.h
    \namespace    Memory
    \brief		

	/////////////////////////////////////////////////////////////////////////////
		TODO:
			- Heap: TODO
			- end of block marking
	/////////////////////////////////////////////////////////////////////////////
*/
/******************************************************************************/
/*** Include guard ************************************************************/
#ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H
/*** Includes *****************************************************************/
/*** Forward Declarations *****************************************************/
/*** Macros *******************************************************************/
#define DUMP_MEMORY Memory::MemoryManager::GetInstance()->DumpAllHeaps();
#define MY_NEW(heapID, Tag) new ((Memory::HID) heapID,__FILE__,__LINE__,Tag)
#define MY_DELETE(mem) delete(mem);
#define MY_DELETE_ARRAY(mem) delete[](mem);
#define MY_ALLOC(size) Memory::MemoryManager::GetInstance()->GetDefaultHeap()->AllocateBlock(size,__FILE__,__LINE__,Tag)
#define MY_FREE(mem) Memory::MemoryManager::GetInstance()->Free(mem)
/*** Namespace ****************************************************************/
namespace Memory
{
/*** Constants ****************************************************************/
const int NAME_LENGTH = 32;			//!<
const int MEM_END_MARKER = 44;		//!<
const int NUM_OF_HEAPS = 6;			//!<
const int HEAP_SIZE = 10000*10000;		//!<
/*** Interface ****************************************************************/
/*
	\brief Allocation Information
*/
struct AllocInfo
{
	char* File;			//!<
	double Line;		//!<
	const char* Tag;	//!<
};
/*
	\brief Allocation Header
*/
struct AllocHeader
{
	int Size;				//!<
	int Signature;			//!<
	bool Used;				//!<
	AllocHeader* Next;		//!<
	AllocHeader* Previous;	//!<
	AllocInfo AllocInfo;	//!<
};
/*
	\brief Heap Identification
*/
typedef enum HID
{
	HID_Default = 0,
	HID_Game,
	HID_Engine,
	HID_Dynamic,
	HID_Rendering,
	HID_Physics,
	//
	HID_Count
};

class MemoryManager
{
	class Heap
	{
	public:
		Heap(const char* name, int size);

		virtual ~Heap(void);

		const char* GetName() const;

		int GetSignature() const;

		void* AllocateBlock(size_t size,char * file, double line, const char* tag);

		void FreeBlock(void* memory);

		unsigned int FreeSpace() const;

		void DumpHeapToFile(const char* fileName) const;

		void SetName(const char* name);

		void Init(const char*name , int size);

		static int GetFrontBlockOverHead() { return (int)sizeof(AllocHeader);}

		bool CheckHeapConsistency();

		void UnitTest();

		unsigned int GetSize() const;

		unsigned int UsedSize() const;

		unsigned int GetNumberOfBlocks() const {return mNumberOfBlocks;}

		void* FindBeginningOfMemoryBlock(void* ptr);

		bool CombineBlocks(AllocHeader* b1, AllocHeader* b2);

		void CheckGuard(AllocHeader* block);

		int GetBlockSize(const AllocHeader* block) const;

		int GetBlockOverHead(){return GetFrontBlockOverHead() /*+ GetRearBlockOverHead()*/;}

		//int GetRearBlockOverHead(){} //Bytes at end - guard check

		unsigned int GetNumFreeBlocks();

		unsigned int GetTotalFreeMemory();

		unsigned int GetLargestFreeBlock();

		unsigned int SpaceBetweenBlocks(AllocHeader* block1, AllocHeader* block2);

		int DistanceToEndOfMemory(const AllocHeader* block) const;

		void* EndOfHeader(const AllocHeader* block) const;

		int HashName(const char* name);

		char mName[NAME_LENGTH];			//!<
		int mInitialSize;					//!<
		unsigned int mSize;					//!<
		int mSignature;						//!<
		void* mHeapStart;					//!<
		AllocHeader* mFirstFreeBlock;		//!<
		int mNumberOfBlocks;				//!<
	};

public:
	virtual ~MemoryManager(void);

	static void Initialize();

	static void Deinitialize();

	static MemoryManager* GetInstance();

	void CreateHeap(const char* heapName, int heapSize);

	Heap* GetHeap(int heapNumber);

	void* Allocate(int size, HID heapId, char * file, double line, const char* tag);
	
	void Free(void* memory);

	void DumpAllHeaps();

	void UnitTest();

	unsigned int GetMaxMemory();

	unsigned int GetUsedMemory();

	void Enable();
	
	void Disable();
	 
private:
	MemoryManager(void);

	MemoryManager(const MemoryManager& rhs);

	Heap* GetHeapBySig(int sig);

private:
	Heap* mHeapList;							//!<
	int mMaxNumberOfHeap;						//!<
	int mCurrentNumberOfHeaps;					//!<
	static MemoryManager* sInstance;			//!<
};
}

//Global New/Delete Function Overloads
void *operator new(size_t size, Memory::HID id, char * file, double line, const char* tag);

void operator delete(void* mem, Memory::HID id, char * file, double line, const char* tag);

void* operator new[](size_t size);

void* operator new[](size_t size, Memory::HID heapId, char * file, double line, const char* tag);

void operator delete[](void* ptr);

void operator delete[](void* ptr, Memory::HID heapId, char * file, double line, const char* tag);

#endif//MEMORYMANAGER_H